﻿// Copyright (C) 2012 Jeff Tanner <jeff00seattle@gmail.com>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

using System;
using System.IO;
using System.Diagnostics;
using System.Configuration;
using System.Configuration.Install;
using System.ComponentModel;
using System.Text.RegularExpressions;
using System.Collections.Generic;

using WindowsAzure_REST;

namespace WindowsAzure_FileBackup_Common
{
    partial class Common
    {
        /// <summary>
        /// Allowed file metadata
        /// </summary>
        public enum EnumFileMetadata
        {
            FileName,
            Attributes,
            CreationTimeUtc,
            LastAccessTimeUtc,
            LastWriteTimeUtc,
            RelativePath,
            PathWithName,
            Size,
            IsDirectory
        }

        ////////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>   Gets a relative path. </summary>
        ///
        /// <param name="rootDirectory">    Pathname of the root directory. </param>
        /// <param name="filePath">         Full pathname of the file. </param>
        /// <param name="relativePath">     [out] Full pathname of the relative file. </param>
        ///
        /// <returns>   true if it succeeds, false if it fails. </returns>
        ////////////////////////////////////////////////////////////////////////////////////////////////////

        public static bool GetRelativePath(string rootDirectory, string filePath, out string relativePath)
        {
            relativePath = String.Empty;
            DirectoryInfo directory = new DirectoryInfo(rootDirectory);
            FileInfo file = new FileInfo(filePath);
            string fullDirectory = directory.FullName;
            string fullFile = file.FullName;
            if (!fullFile.StartsWith(fullDirectory))
            {
                return false;
            }

            relativePath = fullFile.Substring(fullDirectory.Length + 1);
            return true;
        }

        ////////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>   Sets up associated file metadata for the given blob. </summary>
        ///
        /// <param name="rootDirectory">    Pathname of the root directory. </param>
        /// <param name="filePath">         Full pathname of the file. </param>
        /// <param name="fileMetadata">     The file metadata. </param>
        ////////////////////////////////////////////////////////////////////////////////////////////////////

        public static void SetupMetadata(
            string rootDirectory,
            string filePath,
            SortedList<string, string> fileMetadata
            )
        {
            FileInfo fileInfo = new FileInfo(filePath);

            // Create metadata to be associated with the blob 
            fileMetadata[EnumFileMetadata.FileName.ToString()] = fileInfo.FullName;
            fileMetadata[EnumFileMetadata.Attributes.ToString()] = ((long)fileInfo.Attributes).ToString();
            fileMetadata[EnumFileMetadata.CreationTimeUtc.ToString()] = fileInfo.CreationTimeUtc.ToString();
            fileMetadata[EnumFileMetadata.LastAccessTimeUtc.ToString()] = fileInfo.LastAccessTimeUtc.ToString();
            fileMetadata[EnumFileMetadata.LastWriteTimeUtc.ToString()] = fileInfo.LastWriteTimeUtc.ToString();

            string relativePath = String.Empty;

            if (Common.GetRelativePath(rootDirectory, filePath, out relativePath)
                && !String.IsNullOrEmpty(relativePath))
            {
                fileMetadata[EnumFileMetadata.RelativePath.ToString()] = relativePath;
            }
            fileMetadata[EnumFileMetadata.PathWithName.ToString()] = filePath;
            fileMetadata[EnumFileMetadata.Size.ToString()] = fileInfo.Length.ToString();
            fileMetadata[EnumFileMetadata.IsDirectory.ToString()] = Directory.Exists(filePath).ToString();
        }

        /// <summary>
        /// Handles the OnChanged event of the FileMonitor control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.IO.FileSystemEventArgs"/> instance containing the event data.</param>
        public void FileMonitor_OnChanged(object sender, System.IO.FileSystemEventArgs e)
        {
            try
            {
                string changeType = e.ChangeType.ToString();

                string filePath = e.FullPath;
                string blobPath = Common.GetBlobPath(filePath);

                //write a log entry for the appropriate changetype.

                if (0 == String.Compare(changeType, "Created", true))
                {
                    this.EventLog.WriteEntry(String.Format("FileMonitor: OnChanged: Created: File: {0} | Blob: {1}", filePath, blobPath));
                    DirectoryInfo rootInfo = new DirectoryInfo(Common.WindowsAzureFileBackupRootDir.Replace(@"\", @"\\"));
                    string rootPath = rootInfo.FullName;
                    this.BlobCreate(rootPath, filePath, blobPath);
                }
                else if (0 == String.Compare(changeType, "Deleted", true))
                {
                    this.EventLog.WriteEntry(String.Format("FileMonitor: OnChanged: Deleted: File: {0} | Blob: {1}", filePath, blobPath));
                    this.BlobDelete(filePath, blobPath);
                }
                else if (0 == String.Compare(changeType, "Changed", true))
                {
                    this.EventLog.WriteEntry(String.Format("FileMonitor: OnChanged: Changed: File: {0} | Blob: {1}", filePath, blobPath));
                    this.blobChange(filePath, blobPath);
                }
                else
                {
                    this.EventLog.WriteEntry(
                        String.Format("FileMonitor: OnChanged: {0}: File: {1} | Blob: {2}", changeType, filePath, blobPath),
                        EventLogEntryType.Warning
                        );
                }
            }
            catch (Exception ex)
            {
                this.EventLog.WriteEntry(
                    String.Format("FileMonitor: OnChanged: Exception: {0}", ex.Message),
                    EventLogEntryType.Error
                    );
            }
        }

        /// <summary>
        /// Handles the OnRenamed event of the FileMonitor control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.IO.RenamedEventArgs"/> instance containing the event data.</param>
        public void FileMonitor_OnRenamed(object sender, System.IO.RenamedEventArgs e)
        {
            this.EventLog.WriteEntry(
                String.Format(
                    "FileMonitor: OnRenamed: Renamed: File: {0} {1} | {2} {3}",
                    e.OldFullPath, e.OldName, e.FullPath, e.Name
                    )
                );
            this.BlobRename(e.OldFullPath, e.OldName, e.FullPath, e.Name);
        }

        /// <summary>
        /// Handles the OnError event of the FileMonitor control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.IO.ErrorEventArgs"/> instance containing the event data.</param>
        public void FileMonitor_OnError(object sender, ErrorEventArgs e)
        {
            this.EventLog.WriteEntry(String.Format("FileMonitor: OnError: {0}", e.ToString()));
        }
    }
}
